home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / save.c < prev    next >
C/C++ Source or Header  |  1993-01-11  |  20KB  |  865 lines

  1. /*    SCCS Id: @(#)save.c    3.1    93/01/07    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "lev.h"
  7.  
  8. #ifndef NO_SIGNAL
  9. #include <signal.h>
  10. #endif /* !NO_SIGNAL */
  11. #if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
  12. #include <fcntl.h>
  13. #endif /* EXPLORE_MODE */
  14.  
  15. boolean hu;        /* set during hang-up */
  16.  
  17. #ifdef MULDGN
  18. #include "quest.h"
  19. #endif
  20.  
  21. #ifdef MFLOPPY
  22. extern struct finfo fileinfo[];
  23. long bytes_counted;
  24. static int count_only;
  25. #else
  26. extern boolean level_exists[];
  27. #endif
  28.  
  29. #ifdef MICRO
  30. int dotcnt;    /* also used in restore */
  31. #endif
  32.  
  33. #ifdef ZEROCOMP
  34. static void FDECL(bputc, (UCHAR_P));
  35. #endif
  36. static void FDECL(savelevchn, (int, int));
  37. static void FDECL(savedamage, (int,struct damage *, int));
  38. static void FDECL(saveobjchn, (int,struct obj *, int));
  39. static void FDECL(savemonchn, (int,struct monst *, int));
  40. static void FDECL(savetrapchn, (int,struct trap *, int));
  41. static void FDECL(savegenoinfo, (int));
  42. static void FDECL(savegamestate, (int, int));
  43. #ifdef MFLOPPY
  44. static void FDECL(savelev0, (int,XCHAR_P,int));
  45. static boolean NDECL(swapout_oldest);
  46. static void FDECL(copyfile, (char *,char *));
  47. #endif /* MFLOPPY */
  48. #ifdef GCC_WARN
  49. static long nulls[10];
  50. #else
  51. #define nulls nul
  52. #endif
  53.  
  54. int
  55. dosave()
  56. {
  57.     clear_nhwindow(WIN_MESSAGE);
  58.     if(yn("Really save?") == 'n') {
  59.         clear_nhwindow(WIN_MESSAGE);
  60.         if(multi > 0) nomul(0);
  61.     } else {
  62.         clear_nhwindow(WIN_MESSAGE);
  63.         pline("Saving...");
  64.         mark_synch();    /* flush output */
  65.         hu = FALSE;
  66.         if(dosave0()) {
  67.             /* make sure they see the Saving message */
  68.             display_nhwindow(WIN_MESSAGE, TRUE);
  69.             exit_nhwindows("Be seeing you...");
  70.             terminate(0);
  71.         } else (void)doredraw();
  72.     }
  73.     return 0;
  74. }
  75.  
  76. #ifndef NOSAVEONHANGUP
  77. int
  78. hangup() {
  79.     if(!hu) {
  80.         hu = TRUE;
  81.         (void) dosave0();
  82. # ifndef VMS
  83.         terminate(1);
  84. # endif
  85.     }
  86.     return 0;
  87. }
  88. #endif
  89.  
  90. /* returns 1 if save successful */
  91. int
  92. dosave0()
  93. {
  94.     register int fd, ofd;
  95.     xchar ltmp;
  96. #ifdef MFLOPPY
  97.     long fds, needed;
  98. #endif
  99.  
  100.     if (!SAVEF[0])
  101.         return 0;
  102.  
  103. #if defined(UNIX) || defined(VMS)
  104.     (void) signal(SIGHUP, SIG_IGN);
  105. #endif
  106. #ifndef NO_SIGNAL
  107.     (void) signal(SIGINT, SIG_IGN);
  108. #endif
  109.  
  110. #if defined(MICRO) && defined(MFLOPPY)
  111.     if(!hu && !saveDiskPrompt(0))    return 0;
  112. #endif
  113.  
  114. #ifdef EXPLORE_MODE
  115.     if(!hu && flags.window_inited) {
  116.         fd = open_savefile();
  117.         if (fd > 0) {
  118.         (void) close(fd);
  119.         clear_nhwindow(WIN_MESSAGE);
  120.         pline("There seems to be an old save file.");
  121.         if (yn("Overwrite the old file?") == 'n') return 0;
  122.         }
  123.     }
  124. #endif
  125.     
  126.     fd = create_savefile();
  127.  
  128.     if(fd < 0) {
  129.         if(!hu) pline("Cannot open save file.");
  130.         (void) delete_savefile();    /* ab@unido */
  131.         return(0);
  132.     }
  133.     if(flags.moonphase == FULL_MOON)    /* ut-sally!fletcher */
  134.         change_luck(-1);        /* and unido!ab */
  135.     if(flags.friday13)
  136.         change_luck(1);
  137.     if(flags.window_inited)
  138.         clear_nhwindow(WIN_MESSAGE);
  139.  
  140. #ifdef MFLOPPY
  141.     if(!hu) {
  142.         dotcnt = 0;
  143.         curs(WIN_MAP, 1, 1);
  144.         putstr(WIN_MAP, 0, "Saving:");
  145.     }
  146.     /* make sure there is enough disk space */
  147.     savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
  148.     savegamestate(fd, COUNT_SAVE);
  149.     needed = bytes_counted;
  150.     for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
  151.         if (ltmp != ledger_no(&u.uz) && fileinfo[ltmp].where)
  152.             needed += fileinfo[ltmp].size + (sizeof ltmp);
  153. # ifdef AMIGA
  154.     needed+=ami_wbench_iconsize(SAVEF);
  155. # endif
  156.     fds = freediskspace(SAVEF);
  157.     if(needed > fds) {
  158.         if(!hu) {
  159.         pline("There is insufficient space on SAVE disk.");
  160.         pline("Require %ld bytes but only have %ld.", needed, fds);
  161.         }
  162.         flushout();
  163.         (void) close(fd);
  164.         (void) delete_savefile();
  165.         return 0;
  166.     }
  167. #endif /* MFLOPPY */
  168.  
  169.     bufon(fd);
  170.     savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
  171.     savegamestate(fd, WRITE_SAVE | FREE_SAVE);
  172.  
  173.     for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
  174.         if (ltmp == ledger_no(&u.uz)) continue;
  175. #ifdef MFLOPPY
  176.         if (!fileinfo[ltmp].where) continue;
  177. #else
  178.         if(!level_exists[ltmp]) continue;
  179. #endif
  180. #ifdef MICRO
  181.         if(!hu) {
  182.             curs(WIN_MAP, 8 + dotcnt++, 1);
  183.             putstr(WIN_MAP, 0, ".");
  184.         }
  185. #endif
  186.         ofd = open_levelfile(ltmp);
  187.         if(ofd < 0) {
  188.             if(!hu) pline("Cannot read level %d.", ltmp);
  189.             (void) close(fd);
  190.             (void) delete_savefile();
  191.             if(!hu) done(TRICKED);
  192.             return(0);
  193.         }
  194.         minit();    /* ZEROCOMP */
  195.         getlev(ofd, hackpid, ltmp, FALSE);
  196.         (void) close(ofd);
  197.         bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
  198.         savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/
  199.         delete_levelfile(ltmp);
  200.     }
  201.     bclose(fd);
  202.  
  203.     /* get rid of current level --jgm */
  204.     delete_levelfile(ledger_no(&u.uz));
  205.     delete_levelfile(0);
  206.     compress(SAVEF);
  207. #ifdef AMIGA
  208.     ami_wbench_iconwrite(SAVEF);
  209. #endif
  210.     return(1);
  211. }
  212.  
  213. static void
  214. savegamestate(fd, mode)
  215. register int fd, mode;
  216. {
  217.     int tmp;        /* not register ! */
  218.  
  219. #ifdef MFLOPPY
  220.     count_only = (mode & COUNT_SAVE);
  221. #endif
  222.     saveobjchn(fd, invent, mode);
  223.     saveobjchn(fd, migrating_objs, mode);
  224.     savemonchn(fd, migrating_mons, mode);
  225.     savegenoinfo(fd);
  226.     tmp = getuid();
  227.     bwrite(fd, (genericptr_t) &tmp, sizeof tmp);
  228.     bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
  229.     bwrite(fd, (genericptr_t) &u, sizeof(struct you));
  230.     save_dungeon(fd);
  231.     bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
  232.     savelevchn(fd, mode);
  233.     bwrite(fd, (genericptr_t) &moves, sizeof moves);
  234.     bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
  235. #ifdef MULDGN
  236.     bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
  237. #endif
  238.     bwrite(fd, (genericptr_t) spl_book, 
  239.                 sizeof(struct spell) * (MAXSPELL + 1));
  240.     save_artifacts(fd);
  241.     save_oracles(fd);
  242.     if(u.ustuck)
  243.         bwrite(fd, (genericptr_t) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
  244.     bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
  245. #ifdef TUTTI_FRUTTI
  246.     bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
  247.     bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
  248.     savefruitchn(fd, mode);
  249. #endif
  250.     savenames(fd);
  251.     save_waterlevel(fd);
  252.     bflush(fd);
  253. }
  254.  
  255. #ifdef INSURANCE
  256. void
  257. savestateinlock()
  258. {
  259.     int fd, hpid;
  260.     static boolean havestate = TRUE;
  261.  
  262.     /* When checkpointing is on, the full state needs to be written
  263.      * on each checkpoint.  When checkpointing is off, only the pid
  264.      * needs to be in the level.0 file, so it does not need to be
  265.      * constantly rewritten.  When checkpointing is turned off during
  266.      * a game, however, the file has to be rewritten once to truncate
  267.      * it and avoid restoring from outdated information.
  268.      *
  269.      * Restricting havestate to this routine means that an additional
  270.      * noop pid rewriting will take place on the first "checkpoint" after
  271.      * the game is started or restored, if checkpointing is off.
  272.      */
  273.     if (flags.ins_chkpt || havestate) {
  274.         /* save the rest of the current game state in the lock file,
  275.          * following the original int pid, the current level number,
  276.          * and the current savefile name, which should not be subject
  277.          * to any internal compression schemes since they must be
  278.          * readable by an external utility
  279.          */
  280.         fd = open_levelfile(0);
  281.         if (fd < 0) {
  282.             pline("Cannot open level 0.");
  283.             pline("Probably someone removed it.");
  284.             done(TRICKED);
  285.             return;
  286.         }
  287.  
  288.         (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
  289.         if (hackpid != hpid) {
  290.             pline("Level 0 pid bad!");
  291.             done(TRICKED);
  292.         }
  293.         (void) close(fd);
  294.  
  295.         fd = create_levelfile(0);
  296.         if (fd < 0) {
  297.             pline("Cannot rewrite level 0.");
  298.             done(TRICKED);
  299.             return;
  300.         }
  301.         (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
  302.         if (flags.ins_chkpt) {
  303.             int currlev = ledger_no(&u.uz);
  304.  
  305.             (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
  306.             save_savefile_name(fd);
  307.             bufon(fd);
  308.             savegamestate(fd, WRITE_SAVE);
  309.         }
  310.         bclose(fd);
  311.     }
  312.     havestate = flags.ins_chkpt;
  313. }
  314. #endif
  315.  
  316. #ifdef MFLOPPY
  317. boolean
  318. savelev(fd, lev, mode)
  319. int fd;
  320. xchar lev;
  321. int mode;
  322. {
  323.     if (mode & COUNT_SAVE) {
  324.         bytes_counted = 0;
  325.         savelev0(fd, lev, COUNT_SAVE);
  326.         while (bytes_counted > freediskspace(levels))
  327.             if (!swapout_oldest())
  328.                 return FALSE;
  329.     }
  330.     if (mode & WRITE_SAVE) {
  331.         bytes_counted = 0;
  332.         /* mode is WRITE_SAVE and possibly FREE_SAVE */
  333.         savelev0(fd, lev, mode);
  334.     }
  335.     fileinfo[lev].where = ACTIVE;
  336.     fileinfo[lev].time = moves;
  337.     fileinfo[lev].size = bytes_counted;
  338.     return TRUE;
  339. }
  340.  
  341. static void
  342. savelev0(fd,lev,mode)
  343. #else
  344. void
  345. savelev(fd,lev,mode)
  346. #endif
  347. int fd;
  348. xchar lev;
  349. int mode;
  350. {
  351. #ifdef TOS
  352.     short tlev;
  353. #endif
  354.  
  355.     if(fd < 0) panic("Save on bad file!");    /* impossible */
  356. #ifdef MFLOPPY
  357.     count_only = (mode & COUNT_SAVE);
  358. #else
  359.     if(lev >= 0 && lev <= maxledgerno()) level_exists[lev] = TRUE;
  360. #endif
  361.     bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
  362. #ifdef TOS
  363.     tlev=lev; tlev &= 0x00ff;
  364.     bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
  365. #else
  366.     bwrite(fd,(genericptr_t) &lev,sizeof(lev));
  367. #endif
  368. #ifdef RLECOMP
  369.     {
  370.         /* perform run-length encoding of rm structs */
  371.         struct rm *prm, *rgrm;
  372.         int x, y;
  373.         uchar match;
  374.         
  375.         rgrm = &levl[0][0];        /* start matching at first rm */
  376.         match = 0;
  377.  
  378.         for (y = 0; y < ROWNO; y++) {
  379.         for (x = 0; x < COLNO; x++) {
  380.             prm = &levl[x][y];
  381.             if (prm->glyph == rgrm->glyph
  382.             && prm->typ == rgrm->typ
  383.             && prm->seen == rgrm->seen
  384.             && prm->lit == rgrm->lit
  385.             && prm->doormask == rgrm->doormask
  386.             && prm->horizontal == rgrm->horizontal
  387.             && prm->waslit == rgrm->waslit
  388.             && prm->roomno == rgrm->roomno
  389.             && prm->edge == rgrm->edge) {
  390.             match++;
  391.             if (match > 254) {
  392.                 match = 254;    /* undo this match */
  393.                 goto writeout;
  394.             }
  395.             } else {
  396.             /* the run has been broken,
  397.              * write out run-length encoding */
  398.             writeout:
  399.             bwrite(fd, (genericptr_t)&match, sizeof(uchar));
  400.             bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
  401.             /* start encoding again. we have at least 1 rm
  402.              * in the next run, viz. this one. */
  403.             match = 1;    
  404.             rgrm = prm;
  405.             }
  406.         }
  407.         }
  408.         if (match > 0) {
  409.         bwrite(fd, (genericptr_t)&match, sizeof(uchar));
  410.         bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
  411.         }
  412.     }
  413. #else
  414.     bwrite(fd,(genericptr_t) levl,sizeof(levl));
  415. #endif /* RLECOMP */
  416.  
  417.     bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
  418.     bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
  419.     bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
  420.     bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
  421.     bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
  422.     bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
  423.     bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
  424.     bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
  425.     bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
  426.     savemonchn(fd, fmon, mode);
  427.     save_worm(fd, mode);    /* save worm information */
  428.     savetrapchn(fd, ftrap, mode);
  429.     saveobjchn(fd, fobj, mode);
  430.     saveobjchn(fd, billobjs, mode);
  431.  
  432.     save_engravings(fd, mode);
  433.     save_rooms(fd);
  434.     bwrite(fd,(genericptr_t) doors,sizeof(doors));
  435.     savedamage(fd, level.damagelist, mode);
  436.     if (mode & FREE_SAVE) {
  437.         billobjs = 0;
  438.         ftrap = 0;
  439.         fmon = 0;
  440.         fobj = 0;
  441.     }
  442.     bflush(fd);
  443. }
  444.  
  445. #ifdef ZEROCOMP
  446. /* The runs of zero-run compression are flushed after the game state or a
  447.  * level is written out.  This adds a couple bytes to a save file, where
  448.  * the runs could be mashed together, but it allows gluing together game
  449.  * state and level files to form a save file, and it means the flushing
  450.  * does not need to be specifically called for every other time a level
  451.  * file is written out.
  452.  */
  453.  
  454. #define RLESC '\0'    /* Leading character for run of LRESC's */
  455. #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
  456.  
  457. #ifndef ZEROCOMP_BUFSIZ
  458. #define ZEROCOMP_BUFSIZ BUFSZ
  459. #endif
  460. static unsigned char NEARDATA outbuf[ZEROCOMP_BUFSIZ];
  461. static unsigned short NEARDATA outbufp = 0;
  462. static short NEARDATA outrunlength = -1;
  463. static int NEARDATA bwritefd;
  464.  
  465. /*dbg()
  466. {
  467.    if(!hu) printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
  468. }*/
  469.  
  470. static void
  471. bputc(c)
  472. unsigned char c;
  473. {
  474. #ifdef MFLOPPY
  475.     bytes_counted++;
  476.     if (count_only)
  477.       return;
  478. #endif
  479.     if (outbufp >= sizeof outbuf) {
  480.     (void) write(bwritefd, outbuf, sizeof outbuf);
  481.     outbufp = 0;
  482.     }
  483.     outbuf[outbufp++] = c;
  484. }
  485.  
  486. /*ARGSUSED*/
  487. void
  488. bufon(fd)
  489.     int fd;
  490. {
  491.     return;
  492. }
  493.  
  494. void
  495. bflush(fd)  /* flush run and buffer */
  496. register int fd;
  497. {
  498.       bwritefd = fd;
  499.       if (outrunlength >= 0) {    /* flush run */
  500.       flushoutrun(outrunlength);
  501.       }
  502.       if (outbufp) {
  503. #ifdef MFLOPPY
  504.       if (!count_only)    /* flush buffer */
  505. #endif
  506.           (void) write(fd, outbuf, outbufp);
  507.       outbufp = 0;
  508.       }
  509.       /*printf("bflush()"); getret();*/
  510. }
  511.  
  512. void
  513. bwrite(fd, loc, num)
  514. register int fd;
  515. genericptr_t loc;
  516. register unsigned num;
  517. {
  518.       bwritefd = fd;
  519.       for (; num; num--, (*(char **)&loc)++) {
  520.           if (*((char *)loc) == RLESC) { /* One more char in run */
  521.           if (++outrunlength == 0xFF) {
  522.               flushoutrun(outrunlength);
  523.           }
  524.           } else { /* end of run */
  525.           if (outrunlength >= 0) {    /* flush run */
  526.               flushoutrun(outrunlength);
  527.           }
  528.           bputc(*((char *)loc));
  529.           }
  530.       }
  531. }
  532.  
  533. void
  534. bclose(fd)
  535.     int fd;
  536. {
  537.     if (outbufp)
  538.     panic("closing file with buffered data still unwritten");
  539.     (void) close(fd);
  540. }
  541.  
  542. #else /* ZEROCOMP */
  543.  
  544. static int bw_fd = -1;
  545. static FILE *bw_FILE = 0;
  546.  
  547. void
  548. bufon(fd)
  549.     int fd;
  550. {
  551. #ifdef UNIX
  552.     if(bw_fd >= 0)
  553.     panic("double buffering unexpected");
  554.     bw_fd = fd;
  555.     if((bw_FILE = fdopen(fd, "w")) == 0)
  556.     panic("buffering of file %d failed", fd);
  557. #endif
  558. }
  559.  
  560. void
  561. bflush(fd)
  562.     int fd;
  563. {
  564. #ifdef UNIX
  565.     if(fd == bw_fd) {
  566.     if(fflush(bw_FILE) == EOF)
  567.         panic("flush of savefile failed!");
  568.     }
  569. #endif
  570.     return;
  571. }
  572.  
  573. void
  574. bwrite(fd,loc,num)
  575. register int fd;
  576. register genericptr_t loc;
  577. register unsigned num;
  578. {
  579. #ifdef MFLOPPY
  580.     bytes_counted += num;
  581.     if (!count_only)
  582. #endif
  583.     {
  584. #ifdef UNIX
  585.         if(fd != bw_fd)
  586.         panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
  587.  
  588.         if(fwrite(loc, (int)num, 1, bw_FILE) != 1)
  589. /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
  590. #else
  591. # if defined(BSD) || defined(ULTRIX)
  592.         if(write(fd, loc, (int)num) != (int)num)
  593. # else /* e.g. SYSV, __TURBOC__ */
  594.         if(write(fd, loc, num) != num)
  595. # endif
  596. #endif
  597.         {
  598.         if(!hu) panic("cannot write %u bytes to file #%d", num, fd);
  599.         else    terminate(1);
  600.         }
  601.     }
  602. }
  603.  
  604. void
  605. bclose(fd)
  606.     int fd;
  607. {
  608.     bflush(fd);
  609. #ifdef UNIX
  610.     if (fd == bw_fd) {
  611.     (void) fclose(bw_FILE);
  612.     bw_fd = -1;
  613.     bw_FILE = 0;
  614.     return;
  615.     }
  616. #endif
  617.     (void) close(fd);
  618. }
  619. #endif /* ZEROCOMP */
  620.  
  621. static void
  622. savelevchn(fd, mode)
  623. register int fd, mode;
  624. {
  625.     int cnt = 0;
  626.     s_level    *tmplev, *tmplev2;
  627.  
  628.     for(tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
  629.     bwrite(fd, (genericptr_t) &cnt, sizeof(int));
  630.  
  631.     for(tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
  632.  
  633.         tmplev2 = tmplev->next;
  634.         bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
  635.         if (mode & FREE_SAVE)
  636.         free((genericptr_t) tmplev);
  637.     }
  638. }
  639.  
  640. static void
  641. savedamage(fd, damageptr, mode)
  642. register int fd, mode;
  643. register struct damage *damageptr;
  644. {
  645.     register struct damage *tmp_dam;
  646.     unsigned int xl = 0;
  647.  
  648.     for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) 
  649.         xl++;
  650.     bwrite(fd, (genericptr_t) &xl, sizeof(xl));
  651.     while (xl--) {
  652.         bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); 
  653.         tmp_dam = damageptr;
  654.         damageptr = damageptr->next;
  655.         if (mode & FREE_SAVE)
  656.         free((genericptr_t)tmp_dam);
  657.     }
  658.     if (mode & FREE_SAVE)
  659.         level.damagelist = 0;
  660. }
  661.  
  662. static void
  663. saveobjchn(fd,otmp,mode)
  664. register int fd, mode;
  665. register struct obj *otmp;
  666. {
  667.     register struct obj *otmp2;
  668.     unsigned int xl;
  669.     int minusone = -1;
  670.  
  671.     while(otmp) {
  672.         otmp2 = otmp->nobj;
  673.         xl = otmp->onamelth;
  674.         bwrite(fd, (genericptr_t) &xl, sizeof(int));
  675.         bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
  676.  
  677.         if (Is_container(otmp) || otmp->otyp == STATUE)
  678.         saveobjchn(fd,otmp->cobj,mode);
  679.         if (mode & FREE_SAVE)
  680.         dealloc_obj(otmp);
  681.         otmp = otmp2;
  682.     }
  683.     bwrite(fd, (genericptr_t) &minusone, sizeof(int));
  684. }
  685.  
  686. static void
  687. savemonchn(fd,mtmp,mode)
  688. register int fd, mode;
  689. register struct monst *mtmp;
  690. {
  691.     register struct monst *mtmp2;
  692.     unsigned int xl;
  693.     int minusone = -1;
  694.     struct permonst *monbegin = &mons[0];
  695.  
  696.     bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
  697.  
  698.     while(mtmp) {
  699.         mtmp2 = mtmp->nmon;
  700. #ifdef MUSE
  701.         if (mtmp->mw && mtmp->mw != mtmp->minvent) sort_mwep(mtmp);
  702. #endif
  703.         xl = mtmp->mxlth + mtmp->mnamelth;
  704.         bwrite(fd, (genericptr_t) &xl, sizeof(int));
  705.         bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
  706.         if(mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode);
  707.         if (mode & FREE_SAVE)
  708.             dealloc_monst(mtmp);
  709.         mtmp = mtmp2;
  710.     }
  711.     bwrite(fd, (genericptr_t) &minusone, sizeof(int));
  712. }
  713.  
  714. static void
  715. savetrapchn(fd,trap,mode)
  716. register int fd,mode;
  717. register struct trap *trap;
  718. {
  719.     register struct trap *trap2;
  720.     while(trap) {
  721.         trap2 = trap->ntrap;
  722.         bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
  723.         if (mode & FREE_SAVE)
  724.             dealloc_trap(trap);
  725.         trap = trap2;
  726.     }
  727.     bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
  728. }
  729.  
  730. #ifdef TUTTI_FRUTTI
  731. /* save all the fruit names and ID's; this is used only in saving whole games
  732.  * (not levels) and in saving bones levels.  When saving a bones level,
  733.  * we only want to save the fruits which exist on the bones level; the bones
  734.  * level routine marks nonexistent fruits by making the fid negative.
  735.  */
  736. void
  737. savefruitchn(fd, mode)
  738. register int fd, mode;
  739. {
  740.     register struct fruit *f2, *f1;
  741.  
  742.     f1 = ffruit;
  743.     while(f1) {
  744.         f2 = f1->nextf;
  745.         if (f1->fid >= 0) {
  746.             bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
  747.         }
  748.         if (mode & FREE_SAVE)
  749.             dealloc_fruit(f1);
  750.         f1 = f2;
  751.     }
  752.     bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
  753. }
  754. #endif
  755.  
  756. static void
  757. savegenoinfo(fd)
  758. register int fd;
  759. {
  760.     register int i;
  761.     unsigned genolist[NUMMONS];
  762.  
  763.     for (i = 0; i < NUMMONS; i++)
  764.         genolist[i] = mons[i].geno;
  765.  
  766.     bwrite(fd, (genericptr_t) genolist, sizeof(genolist));
  767. }
  768.  
  769. #ifdef MFLOPPY
  770. boolean
  771. swapin_file(lev)
  772. int lev;
  773. {
  774.     char to[PATHLEN], from[PATHLEN];
  775.  
  776.     Sprintf(from, "%s%s", permbones, alllevels);
  777.     Sprintf(to, "%s%s", levels, alllevels);
  778.     set_levelfile_name(from, lev);
  779.     set_levelfile_name(to, lev);
  780.     while (fileinfo[lev].size > freediskspace(to))
  781.         if (!swapout_oldest())
  782.             return FALSE;
  783. # ifdef WIZARD
  784.     if (wizard) {
  785.         pline("Swapping in `%s'", from);
  786.         wait_synch();
  787.     }
  788. # endif
  789.     copyfile(from, to);
  790.     (void) unlink(from);
  791.     fileinfo[lev].where = ACTIVE;
  792.     return TRUE;
  793. }
  794.  
  795. static boolean
  796. swapout_oldest() {
  797.     char to[PATHLEN], from[PATHLEN];
  798.     int i, oldest;
  799.     long oldtime;
  800.  
  801.     if (!ramdisk)
  802.         return FALSE;
  803.     for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
  804.         if (fileinfo[i].where == ACTIVE
  805.         && (!oldtime || fileinfo[i].time < oldtime)) {
  806.             oldest = i;
  807.             oldtime = fileinfo[i].time;
  808.         }
  809.     if (!oldest)
  810.         return FALSE;
  811.     Sprintf(from, "%s%s", levels, alllevels);
  812.     Sprintf(to, "%s%s", permbones, alllevels);
  813.     set_levelfile_name(from, oldest);
  814.     set_levelfile_name(to, oldest);
  815. # ifdef WIZARD
  816.     if (wizard) {
  817.         pline("Swapping out `%s'.", from);
  818.         wait_synch();
  819.     }
  820. # endif
  821.     copyfile(from, to);
  822.     (void) unlink(from);
  823.     fileinfo[oldest].where = SWAPPED;
  824.     return TRUE;
  825. }
  826.  
  827. static void
  828. copyfile(from, to)
  829. char *from, *to;
  830. {
  831. # ifdef TOS
  832.  
  833.     if (_copyfile(from, to))
  834.         panic("Can't copy %s to %s", from, to);
  835. # else
  836.     char buf[BUFSIZ];    /* this is system interaction, therefore
  837.                  * BUFSIZ instead of NetHack's BUFSZ */
  838.     int nfrom, nto, fdfrom, fdto;
  839.  
  840.     if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
  841.         panic("Can't copy from %s !?", from);
  842.     if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
  843.         panic("Can't copy to %s", to);
  844.     do {
  845.         nfrom = read(fdfrom, buf, BUFSIZ);
  846.         nto = write(fdto, buf, nfrom);
  847.         if (nto != nfrom)
  848.             panic("Copyfile failed!");
  849.     } while (nfrom == BUFSIZ);
  850.     (void) close(fdfrom);
  851.     (void) close(fdto);
  852. # endif /* TOS */
  853. }
  854.  
  855. void
  856. co_false()        /* see comment in bones.c */
  857. {
  858.     count_only = FALSE;
  859.     return;
  860. }
  861.  
  862. #endif /* MFLOPPY */
  863.  
  864. /*save.c*/
  865.